package com.ray.finance.strategy.bill.create;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ray.business.check.PurchaseCheck;
import com.ray.business.enums.PurchaseStatusEnum;
import com.ray.business.enums.SaleStatusEnum;
import com.ray.business.service.*;
import com.ray.business.table.entity.*;
import com.ray.common.AmountUpdate;
import com.ray.finance.builder.AdvanceDetailBuilder;
import com.ray.finance.builder.BillBuilder;
import com.ray.finance.builder.BillPayBuilder;
import com.ray.finance.enums.BillSourceEnum;
import com.ray.finance.enums.BillStatusEnum;
import com.ray.finance.enums.BillTypeEnum;
import com.ray.finance.enums.PayTypeEnum;
import com.ray.finance.service.FinaAdvanceDetailService;
import com.ray.finance.service.FinaAdvanceService;
import com.ray.finance.service.FinaBillPayService;
import com.ray.finance.service.FinaBillService;
import com.ray.finance.table.entity.FinaAdvance;
import com.ray.finance.table.entity.FinaBill;
import com.ray.finance.table.params.bill.BillCreateParams;
import com.ray.magicBlock.Strategy;
import com.ray.magicBlock.anno.Block;
import com.ray.woodencreate.beans.LoginUser;
import com.ray.woodencreate.exception.BusinessExceptionFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

/**
 * @author bo shen
 * @Description: 对账单
 * @Class: PurchaseInService
 * @Package com.ray.wms.strategy.in
 * @date 2020/6/8 15:05
 * @company <p>Ray快速开发平台</p>
 * @updateRecord time(修改时间)  author(修改人)   desc(修改内容)
 */
@Slf4j
@Block(group = "createBill", strategy = "PURCHASE", desc = "采购对账单")
public class PurchaseCreateService implements Strategy<BillCreateParams, LoginUser, String> {

    @Autowired
    private ProdPurchaseService prodPurchaseService;
    @Autowired
    private ProdPurchaseBackService prodPurchaseBackService;
    @Autowired
    private FinaBillService finaBillService;
    @Autowired
    private ProdPurchaseDeductionService prodPurchaseDeductionService;
    @Autowired
    private FinaAdvanceService finaAdvanceService;
    @Autowired
    private FinaAdvanceDetailService finaAdvanceDetailService;
    @Autowired
    private FinaBillPayService finaBillPayService;

    @Override
    public String execute(BillCreateParams createParams, LoginUser loginUser) {
        //查询采购单列表
        List<String> orderNos = createParams.getOrderNos();
        List<ProdPurchase> prodPurchases = prodPurchaseService.listByOrderNos(createParams.getOrderNos(), loginUser);
        if (ObjectUtil.isEmpty(prodPurchases) || prodPurchases.size() != orderNos.size()) {
            log.info("查询到的采购单数量与订单接口数量不一致,参数：{},结果:{}", orderNos.size(), prodPurchases.size());
            throw BusinessExceptionFactory.newException("采购单数量与订单接口数量不一致");
        }
        BillBuilder billBuilder = new BillBuilder();
        //客户数据
        String customerCode = null;
        //总金额
        BigDecimal total = new BigDecimal(0);
        //预付款金额
        BigDecimal advanceTotal = new BigDecimal(0);
        for (ProdPurchase prodPurchase : prodPurchases) {
            if (StrUtil.isBlank(customerCode)) {
                customerCode = prodPurchase.getCustomerCode();
            }
            new PurchaseCheck(prodPurchase).checkNull("").canBill(String.format("采购单[%s]不能对账", prodPurchase.getOrderNo()));
            if (!StrUtil.equals(customerCode, prodPurchase.getCustomerCode())) {
                log.info("客户不一致");
                throw BusinessExceptionFactory.newException("客户不一致");
            }
            total = total.add(NumberUtil.null2Zero(prodPurchase.getTotalAmount()));
            //查询预付款金额
            FinaAdvance advance = finaAdvanceService.queryAdvanceByOrderNo(prodPurchase.getOrderNo(), loginUser);
            if (ObjectUtil.isNotNull(advance)) {
                //可用预付款
                BigDecimal useAdvanceAmount = advance.getAmount().subtract(advance.getUsableAmount());
                //实际使用额度
                BigDecimal realAmount = useAdvanceAmount.compareTo(prodPurchase.getTotalAmount()) < 0 ? useAdvanceAmount : prodPurchase.getTotalAmount();
                advanceTotal = advanceTotal.add(realAmount);
                //操作实际可用额度
                AmountUpdate amountUpdate = new AmountUpdate();
                amountUpdate.setBusinessCode(advance.getAdvanceCode());
                amountUpdate.setUpdateVersion(advance.getUpdateVersion());
                amountUpdate.setAmount(advance.getUsableAmount().add(realAmount));
                if(!finaAdvanceService.updateUsableAmount(amountUpdate,loginUser)){
                    log.info("更新预付单已使用金额异常");
                    throw BusinessExceptionFactory.newException("更新预付单已使用金额异常");
                }
                //插入使用明细
                finaAdvanceDetailService.save(new AdvanceDetailBuilder().appendBillNo(billBuilder.getCode()).appendAmount(realAmount)
                        .appendCode(advance.getAdvanceCode()).appendCreate(loginUser).bulid());
                //生成预付款记录
                finaBillPayService.save(new BillPayBuilder().appendPayType(PayTypeEnum.ADVANCE.getValue()).appendBillNo(billBuilder.getCode())
                        .append(advance).appendAmount(realAmount)
                        .appendCreate(loginUser).bulid());
            }
        }
        //查询是否有未完成的退款单
        Integer count = prodPurchaseBackService.countByOrderNos(orderNos, Arrays.asList(PurchaseStatusEnum.UN_CHECK.getValue(), PurchaseStatusEnum.CHECKED.getValue()), loginUser);
        if (count > 0) {
            log.info("存在操作完成的退回单");
            throw BusinessExceptionFactory.newException("存在操作完成的退回单");
        }
        //查询退款金额
        List<ProdPurchaseBack> prodPurchaseBacks = prodPurchaseBackService.listByOrderNos(orderNos, Arrays.asList(SaleStatusEnum.FINISH.getValue()), loginUser);

        BigDecimal deduction = new BigDecimal(0);
        if (ObjectUtil.isNotEmpty(prodPurchaseBacks)) {
            deduction = prodPurchaseBacks.stream().map(ProdPurchaseBack::getTotalAmount).reduce(BigDecimal::add).get();
        }

        //查询扣款金额
        List<ProdPurchaseDeduction> prodPurchaseDeductions = prodPurchaseDeductionService.listByOrderNos(orderNos, loginUser);

        if (ObjectUtil.isNotEmpty(prodPurchaseDeductions)) {
            deduction = deduction.add(prodPurchaseDeductions.stream().map(ProdPurchaseDeduction::getAmount).reduce(BigDecimal::add).get());
        }

        //查询订单信息的币种信息
        String currency = prodPurchaseService.queryOrderCurrency(orderNos, loginUser);

        billBuilder.appendCreate(loginUser).appendOrderStatus(BillStatusEnum.UN_CHECK.getValue());
        FinaBill finaBill = billBuilder.bulid();
        finaBill.setTotalAmount(total);
        finaBill.setDeductionAmount(deduction);
        finaBill.setAmount(total.subtract(deduction));
        finaBill.setPayAmount(advanceTotal);
        finaBill.setCustomerCode(customerCode);
        finaBill.setCurrency(currency);
        finaBill.setBillType(BillTypeEnum.OUT.getValue());
        finaBill.setBillSource(BillSourceEnum.PURCHASE.getValue());
        //保存
        finaBillService.save(finaBill);
        //保存关联
        if (!prodPurchaseService.comfireBill(orderNos, billBuilder.getCode(), loginUser)) {
            throw BusinessExceptionFactory.newException("完成采购对账异常");
        }
        if (prodPurchaseBackService.countBill(orderNos, loginUser) > 0) {
            if (!prodPurchaseBackService.comfireBill(orderNos, billBuilder.getCode(), loginUser)) {
                throw BusinessExceptionFactory.newException("完成采购退货对账异常");
            }
        }
        return billBuilder.getCode();
    }
}
